#include "anatomicalregion.h"
double colors[9][3] = {{1,0,0},{0,1,0},{1,1,0},{1,0,1},{1,1,1},{0,1,1},{0,0,1},{0.292,0,0.507},{0.93,0.507,0.93}};

AnatomicalRegion::AnatomicalRegion(const RegionInfo &rInfo)
{
    rinfo = rInfo;
    actor = NULL;
    mapper = NULL;
    contourActor = NULL;
    contourMapper = NULL;
    data = NULL;
    NodeRefCount = 0;
    int root = (int)floor((double)rinfo.RegionID/1000);
    color[0] = colors[root][0];
    color[1] = colors[root][1];
    color[2] = colors[root][2];
}

AnatomicalRegion::AnatomicalRegion(const AnatomicalRegion &aRegion)
{
    rinfo = aRegion.rinfo;
    actor = aRegion.actor;
    mapper = aRegion.mapper;
    contourActor = aRegion.contourActor;
    contourMapper = aRegion.contourMapper;
    data = aRegion.data;
    NodeRefCount = aRegion.NodeRefCount;
    color[0] = aRegion.color[0];
    color[1] = aRegion.color[1];
    color[2] = aRegion.color[2];
}

AnatomicalRegion& AnatomicalRegion::operator=(const AnatomicalRegion& aRegion)
{
    rinfo = aRegion.rinfo;
    actor = aRegion.actor;
    mapper = aRegion.mapper;
    contourActor = aRegion.contourActor;
    contourMapper = aRegion.contourMapper;
    data = aRegion.data;
    NodeRefCount = aRegion.NodeRefCount;
    color[0] = aRegion.color[0];
    color[1] = aRegion.color[1];
    color[2] = aRegion.color[2];
    return *this;
}

bool AnatomicalRegion::operator==(AnatomicalRegion aRegion)
{
    return this->equals(&aRegion);
}

AnatomicalRegion::~AnatomicalRegion()
{
    if(actor)
        actor->Delete();
    if(mapper)
        mapper->Delete();
    //if(data)
    //    data->Delete();
    if(contourActor)
        contourActor->Delete();
    if(contourMapper)
        contourMapper->Delete();
}

void AnatomicalRegion::extractPolyDataFrom(vtkDataSet *dataSet)
{
    vtkContourFilter *contour = vtkContourFilter::New();
    vtkImageThreshold *threshold = vtkImageThreshold::New();

    int thresh = rinfo.RegionID;
    threshold->SetInput(dataSet);

    threshold->ThresholdBetween(thresh, thresh);
    threshold->ReplaceOutOn();
    threshold->ReplaceInOff();

    threshold->SetOutValue(0);
    threshold->Update();

    contour->SetValue(0, 0.5);
    contour->SetInput(threshold->GetOutput());
    contour->ComputeGradientsOn();
    contour->ComputeNormalsOn();
    contour->Update();

	data = contour->GetOutput();

	createActorAndMapper(data);

    contour->Delete();
    threshold->Delete();

	createRegionSphere();
}

void AnatomicalRegion::createRegionSphere()
{
    nodeActor = vtkActor::New();
    nodeMapper = vtkPolyDataMapper::New();
    contourActor = vtkActor::New();
    contourMapper = vtkPolyDataMapper::New();
    ssource = vtkSphereSource::New();
    ssource->SetCenter(rinfo.CenterX,rinfo.CenterY,rinfo.CenterZ);
    ssource->SetRadius(2);
    ssource->Update();
    nodeMapper->SetInput(ssource->GetOutput());
    nodeActor->SetMapper(nodeMapper);
	nodeActor->VisibilityOff();
	nodeMapper->SetScalarRange(info().RegionID,info().RegionID);
    ssource->Update();
    nodeMapper->Update();
    ssource->Delete();
}

void AnatomicalRegion::setSphereRadius(double absCor, double min, double max){
	double diff = max-min;
	double perc = (absCor - min)/diff;
	double final = ((MAXRADIUS - MINRADIUS)*perc)+MINRADIUS;
	
	ssource->SetRadius(final);
}

void AnatomicalRegion::loadPolyDataFromFile(std::string fullpath)
{
	vtkXMLPolyDataReader *reader = vtkXMLPolyDataReader::New();
	reader->SetFileName(fullpath.c_str());
	reader->Update();
	
	data = reader->GetOutput();

	createActorAndMapper(data);

	double center[3];
	data->GetCenter(center);	

	rinfo.CenterX = center[0];
	rinfo.CenterY = center[1];
	rinfo.CenterZ = center[2];

	reader->Delete();

	createRegionSphere();
}

void AnatomicalRegion::createActorAndMapper(vtkPolyData *data)
{
    actor = vtkActor::New();

    mapper = vtkPolyDataMapper::New();

    mapper->SetInput(data);
    actor->SetMapper(mapper);

    actor->GetProperty()->SetColor(color[0],color[1],color[2]);
    actor->GetProperty()->SetOpacity(1);
    actor->GetProperty()->BackfaceCullingOn();
	actor->VisibilityOff(); //off by default
    mapper->ScalarVisibilityOff();
    mapper->Update();
    mapper->SetScalarRange(rinfo.RegionID,rinfo.RegionID);
}

void AnatomicalRegion::attachToRenderer(vtkRenderer *renderer)
{
    renderer->AddActor(actor);
}

void AnatomicalRegion::detachFromRenderer(vtkRenderer *renderer)
{
    renderer->RemoveActor(actor);
}

RegionInfo& AnatomicalRegion::info() const
{
    return const_cast<RegionInfo&>(rinfo);
}

vtkActor *AnatomicalRegion::getNodeActor()
{
    return nodeActor;
}

vtkPolyData *AnatomicalRegion::getData()
{
	return data;
}

void AnatomicalRegion::getColor(double col[3])
{
	actor->GetProperty()->GetColor(col);
}

void AnatomicalRegion::resetColor()
{
	actor->GetProperty()->SetColor(color[0],color[1],color[2]);
}

void AnatomicalRegion::setLinkNodeVisible(bool vis)
{
	nodeActor->SetVisibility(vis);
}

void AnatomicalRegion::setVisible(bool visible)
{
	actor->SetVisibility(visible);
}

void AnatomicalRegion::setColor(double col[3])
{
	actor->GetProperty()->SetColor(col[0],col[1],col[2]);
}

void AnatomicalRegion::setOpacity(double opac)
{
	actor->GetProperty()->SetOpacity(opac);
}

bool AnatomicalRegion::equals(AnatomicalRegion *reg)
{
    return info().RegionID == reg->info().RegionID;
}
